package com.gitee.feizns.quickstart.web.spring.boot.autoconfigure.decrypt;

import com.gitee.feizns.dynamic.decrypt.Rsa;
import com.gitee.feizns.quickstart.web.decrypt.Decrypt;
import com.gitee.feizns.quickstart.web.decrypt.DecryptParameterResolver;
import com.gitee.feizns.quickstart.web.decrypt.DecryptServletModelAttributeMethodProcessor;
import com.gitee.feizns.quickstart.web.decrypt.DecryptionAlgorithm;
import com.gitee.feizns.quickstart.web.decrypt.DecryptionAlgorithmPrivateKeySupplier;
import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

/**
 * 自定解密配置类（支持注解：{@link Decrypt}）
 * @see Decrypt
 * @author feizns
 * @since 2019/8/3 0003
 */
@Configuration
@RequiredArgsConstructor
@EnableConfigurationProperties(DecryptProperties.class)
public class DecryptAutoConfiguration {

    /**
     * properties
     */
    private final DecryptProperties properties;

    /**
     * <p>
     *     注意：涉及到前后端传递参数的：前端使用公钥将数据加密之后进行base64编码，
     *     最好最后再将base64的字符url转义一下，避免出现
     *     spring mvc将base64字符中的+替换为空格, 从而导致解密失败的情况
     * </p>
     * @return {@link DecryptionAlgorithm}
     */
    @Bean
    @ConditionalOnMissingBean
    public DecryptionAlgorithm decryptionAlgorithm(DecryptionAlgorithmPrivateKeySupplier keySupplier) {
        return new DefaultDecryptionAlgorithm(keySupplier);
    }

    /**
     * 用于仅修改私钥提供规则的时候使用
     * @return {@link DecryptionAlgorithmPrivateKeySupplier}
     */
    @Bean
    @ConditionalOnMissingBean
    public DecryptionAlgorithmPrivateKeySupplier decryptionAlgorithmPrivateKeySupplier() {
        return properties::getPrivateKey;
    }

    /**
     * @see DecryptWebMvcConfigurer
     * @return {@link DecryptWebMvcConfigurer}
     */
    @Bean
    public DecryptWebMvcConfigurer decryptWebMvcConfigurer(DecryptionAlgorithm algorithm) {
        return new DecryptWebMvcConfigurer(algorithm);
    }

    /**
     * 解密web配置
     * <p>
     *  为GET控制器参数中支持{@link Decrypt}<br/>
     *  为GET参数绑定之后支持{@link Decrypt}
     * </p>
     */
    public static class DecryptWebMvcConfigurer implements WebMvcConfigurer {

        private final DecryptionAlgorithm algorithm;

        public DecryptWebMvcConfigurer(DecryptionAlgorithm algorithm) {
            this.algorithm = algorithm;
        }

        @Override
        public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
            resolvers.add(new DecryptParameterResolver(algorithm));
            resolvers.add(new DecryptServletModelAttributeMethodProcessor(algorithm));
        }

    }

    @AllArgsConstructor
    public static class DefaultDecryptionAlgorithm implements DecryptionAlgorithm {

        private final DecryptionAlgorithmPrivateKeySupplier keySupplier;

        @Override
        public String decrypt(String original) {
            Rsa rsa = Rsa.instance();
            String ret;
            try {
                ret = rsa.decrypt(original, rsa.getPrivateKey(keySupplier.get()));
            } catch (Exception e) {
                throw new DecryptionAlgorithm.DecryptionFailedException(e);
            }
            return ret;
        }

    }

}
